class Compiler {
    constructor(vm){
        this.el = vm.$el
        this.vm = vm

        this.compile(this.el)
    }

    compile(el) {
        let childNodes = el.childNodes
        Array.from(el.childNodes).forEach(node => {
            if(this.isTextNode(node)){
                this.compileText(node)
            }else if(this.isElementNode(node)){
                this.compileElement(node)
            }
        })
    }

    compileElement(node) {
        Array.from(node.attributes).forEach(attr => {
            let attrName = attr.name
            if(this.isDirection(attrName)){
                attrName = attrName.substr(2)
                const key = attr.value
                if(this.isEvent(attrName)){
                    attrName = attrName.substr(3)
                    this.handler(node, key, attrName)
                }else{
                    this.update(node, key, attrName)
                }
            }
        })
    }

    compileText(node) {
        const reg = /\{\{(.+?)\}\}/
        const value = node.textContent
        if(reg.test(value)){
            const key = RegExp.$1.trim()
            node.textContent = value.replace(reg, this.vm[key])
        }
    }

    update(node, key, attrName) {
        let updateFn = this[`${attrName}Updater`]
        updateFn && updateFn(node, this.vm[key])
    }

    handler(node, key, attrName) {
        node.addEventListener(attrName, this.vm[key])
    }

    htmlUpdater(node, value) {
        node.innerHTML = value
    }

    textUpdater(node, value) {
        node.textContent = value
    }

    isDirection(attrName) {
        return attrName.startsWith('v-')
    }

    isEvent(eventName) {
        return eventName.startsWith('on')
    }

    isTextNode(node) {
        return node.nodeType === 3
    }

    isElementNode(node) {
        return node.nodeType === 1
    }
}